package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.api.media.model.po.QueryMediaModel;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 媒资信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {

    @Value("${aliyun.region}")
    private String region;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;



    /**
     * 根据id查询媒资信息-远端服务调用
     * @param mediaId 媒资信息id
     * @return  RestResponse 响应数据
     */
    /*
     * 业务分析：
     *   PS：由于是学成内部微服务间的调用，此功能只需要提供基础数据即可，不需要加上业务逻辑判断
     *   如果为了数据的完整性，可以对传入和传出的参数进行判断
     *
     *   1.判断mediaid是否为空
     *   2.查询数据
     *   3.判断数据是否存在
     *   4.如果存在，使用RestResponse来封装返回
     * */
    @Override
    public RestResponse<MediaDTO> getById4Service(Long mediaId) {
        // 1.判断mediaid是否为空
        if (ObjectUtils.isEmpty(mediaId)){
            ExceptionCast.cast(MediaErrorCode.E_140009);
        }
        // 2.查询数据,判断数据是否存在
        Media media = this.getById(mediaId);
        if (ObjectUtils.isEmpty(media)){
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        // po 转 dto
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);
        RestResponse<MediaDTO> mediaDTORestResponse = new RestResponse<>();
        // 赋值
        mediaDTORestResponse.setResult(mediaDTO);
        // 返回数据
        return mediaDTORestResponse;

    }

    /**
     * 媒资信息审核-运营
     * @param mediaDTO   dto封装类
     */
    @Override
    @Transactional
    public void approveCourse(MediaDTO mediaDTO) {
        // 1、关键数据判断 业务判断
        //判断关键数据 审核意见 媒资信息id 媒资审核状态
        if (ObjectUtils.isEmpty(mediaDTO.getAuditMind()) ||
                ObjectUtils.isEmpty(mediaDTO.getAuditStatus()) ||
                ObjectUtils.isEmpty(mediaDTO.getId())
        ) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }
        //  审核意见不能为空
        // 获取媒资信息对象
        Media media = this.getById(mediaDTO.getId());
        // 媒资信息不为空
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        // 媒资状态不为 0
        if (media.getStatus().equals(CommonEnum.DELETE_FLAG.getCode())){
            ExceptionCast.cast(MediaErrorCode.E_140004);
        }
        // 只有审核状态是通过和审核未通过的能进来
        if (!mediaDTO.getAuditStatus().equals(AuditEnum.AUDIT_PASTED_STATUS.getCode())&&
                !mediaDTO.getAuditStatus().equals(AuditEnum.AUDIT_DISPAST_STATUS.getCode())
        ) {
            ExceptionCast.cast(MediaErrorCode.E_140018);
        }

        // 2、审核媒资信息
        media.setAuditMind(mediaDTO.getAuditMind());
        media.setAuditStatus(mediaDTO.getAuditStatus());
        boolean flag = this.updateById(media);
        if (!flag){
            ExceptionCast.cast(MediaErrorCode.E_140017);
        }
    }

    /**
     * 根据媒资信息id删除媒资信息
     *
     * @param mediaId   媒资信息id
     * @param companyId 机构id
     * @return boolean true false
     */
    @Override
    @Transactional
    public boolean removeMedia(Long mediaId, Long companyId) {
        // 1、判断关键数据
        // mediaId
        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(MediaErrorCode.E_140009);
        }
        // 机构id不能为负数
        if (companyId < 1) {
            ExceptionCast.cast(MediaErrorCode.E_140010);
        }
        // 根据媒资id获取媒资对象
        Media media = this.getById(mediaId);
        // media
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        // 审核状态
        if (media.getAuditStatus().equals(AuditEnum.AUDIT_PASTED_STATUS.getCode())) {
            ExceptionCast.cast(MediaErrorCode.E_140015);
        }
        // 判断当前机构id是否存在，对其进行判断
        if (!ObjectUtils.isEmpty(companyId)) {
            if (!ObjectUtils.nullSafeEquals(media.getCompanyId(), companyId)) {
                ExceptionCast.cast(MediaErrorCode.E_140008);
            }
        }
        // todo:业务数据判断，是否关联课程计划


        // 先删除数据库
        LambdaUpdateWrapper<Media> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(!(ObjectUtils.isEmpty(companyId)), Media::getCompanyId, companyId);
        wrapper.eq(Media::getId, mediaId);
        wrapper.set(Media::getStatus, CommonEnum.DELETE_FLAG.getCodeInt());
        boolean flag = this.update(wrapper);
        if (!flag) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }
        // 再删除阿里云中的视频
        try {
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);
            AliyunVODUtil.deleteVideo(client, media.getFileId());
        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }
        return flag;
    }

    /*
        业务分析：
	1.判断关键数据
		mediaId、companyId
	2.判断业务数据
		媒资信息
			判断是否存在（mediaId、companyId）
			判断媒资类型，如果是视频的话，要获得阿里云视频点播的播放地址
	3.获得媒资资源的路径地址Url
			获得最新的播放地址，从阿里云上获得
			PS：优化--要从缓存中获得url（ps：缓存中必须存在url--1.创建media获得，2.服务端启动时来获得--定时任务）
			缓存中的url---设置缓存中的ttl
	4.返回结果内容
     */

    /**
     * 机构或平台预览课程内容
     *
     * @param companyId 机构id
     * @param mediaId   媒资id
     * @return String 返回字符串
     */
    @Override
    public String getVODUrl(Long mediaId, Long companyId) {
        String playUrl = "";
        // mediaId
        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(MediaErrorCode.E_140009);
        }
        // media
        Media media = this.getById(mediaId);
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        // 判断当前机构id是否存在，对其进行判断
        if (!ObjectUtils.isEmpty(companyId)) {
            if (!ObjectUtils.nullSafeEquals(media.getCompanyId(), companyId)) {
                ExceptionCast.cast(MediaErrorCode.E_140008);
            }
        }
        // 获得媒资资源的路径地址Url
        playUrl = getPlayUrl(media.getFileId());
        // 返回 文件id
        return playUrl;

    }

    //获得媒资资源的路径地址Url
    private String getPlayUrl(String videoId) {
        String playUrl = "";
        try {
            // 初始化客户端对象
            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);

            // 解析响应数据并上传凭证和地址
            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, videoId);

            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();

            if (!(ObjectUtils.isEmpty(playInfoList))) {
                GetPlayInfoResponse.PlayInfo playInfo = playInfoList.get(0);
                playUrl = playInfo.getPlayURL();
            }

        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140014);
        }
        return playUrl;
    }


    /**
     * 分页条件查询课程基本信息数据
     *
     * @param params    {@link PageRequestParams} 分页封装数据
     * @param model     {@link QueryMediaModel} 条件查询封装数据
     * @param companyId Long 教学机构Id值
     * @return PageVO 分页结果封装数据
     */
    @Override
    public PageVO<MediaDTO> queryMediaList(PageRequestParams params, QueryMediaModel model, Long companyId) {
        // 1.判断关键数据
        // 分页数据的合法性
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        // 2.构建分页对象
        Page<Media> basePage = new Page<>(params.getPageNo(), params.getPageSize());

        // 3.构建查询条件对象
        LambdaQueryWrapper<Media> wrapper = new LambdaQueryWrapper<>();

        // 过滤删除的媒资,只显示status为1的课程
        wrapper.eq(Media::getStatus, CommonEnum.USING_FLAG.getCodeInt());

        // 媒资审核状态查询条件 eq
        wrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()), Media::getAuditStatus, model.getAuditStatus());

        // todo:如果companyId等于当前code,则是平台
        if (companyId != MediaErrorCode.E_140000.getCode()) {
            // 媒资名称查询条件 like
            wrapper.like(StringUtil.isNotBlank(model.getFilename()), Media::getFilename, model.getFilename());

            // 媒资类型条件查询 like
            wrapper.like(StringUtil.isNotBlank(model.getType()), Media::getType, model.getType());

            // 添加对公司id的查询条件
            wrapper.eq(!(ObjectUtils.isEmpty(companyId)), Media::getCompanyId, companyId);
        }
        // 4.查询数据内容获得结果
        Page<Media> page = this.page(basePage, wrapper);

        // 获取当前页数据
        List<Media> records = page.getRecords();
        // 获取总条数
        long total = page.getTotal();
        // 创建一个空的集合
        List<MediaDTO> dtos = Collections.emptyList();
        // 判断当前页是否为空
        if (!(CollectionUtils.isEmpty(records))) {
            dtos = MediaConvert.INSTANCE.entitys2dtos(records);
        }
        // 5.构建返回结果数据-PageVo
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());

        return pageVO;
    }


    /*
     * 业务分析：
     *   1.判断关键
     *       companyid  filename  fileid(videoId)
     *   2.给信息数据赋值默认值
     *       auditStatus：未审核
     *
     *   3.保存信息
     *   4.将数据库最新数据返回
     *
     * */

    /**
     * 保存媒资信息
     *
     * @param dto       媒资信息封装
     * @param companyId 机构id
     * @return MediaDTO 返回dto
     */
    @Transactional
    public MediaDTO createMedia(MediaDTO dto, Long companyId) {
        // 机构id
        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }
        // 媒资文件名称
        if (StringUtil.isBlank(dto.getFilename())) {
            ExceptionCast.cast(MediaErrorCode.E_140006);
        }
        // 媒资的file_id不能为空
        if (StringUtil.isBlank(dto.getFileId())) {
            ExceptionCast.cast(MediaErrorCode.E_140007);
        }
        // 获取媒资对象
        Media media = MediaConvert.INSTANCE.dto2entity(dto);
        // 设置默认值
        media.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());
        media.setStatus(String.valueOf(CommonEnum.USING_FLAG.getCodeInt()));
        media.setCompanyId(companyId);
        boolean flag = this.save(media);
        // 判断
        if (!flag) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }
        Media po = this.getById(media.getId());
        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(po);
        // 返回dto
        return mediaDTO;
    }

}